home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue29 / mrecsort / MRECSORT.ZIP / mwFixedRecSort.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-11-30  |  20.6 KB  |  789 lines

  1. {+--------------------------------------------------------------------------+
  2.  | Unit:        mwFixedRecSort
  3.  | Created:     11.97
  4.  | Author:      Martin Waldenburg
  5.  | Copyright    1997, all rights reserved.
  6.  | Description: A buffered sorter for an unlimmited amount of records with a fixed
  7.  |              length using a three-way merge for memory and a buffered
  8.  |              three-way merge  for files.
  9.  | Version:     1.0
  10.  | Status       FreeWare
  11.  | It's provided as is, without a warranty of any kind.
  12.  | You use it at your own risc.
  13.  | E-Mail me at Martin.Waldenburg@t-online.de
  14.  +--------------------------------------------------------------------------+}
  15.  
  16. unit mwFixedRecSort;
  17.  
  18. {$R-}
  19.  
  20.  
  21.  
  22. interface
  23.  
  24. uses SysUtils, Windows, Classes;
  25.  
  26. type
  27.   TMergeCompare = function (Item1, Item2: Pointer): Integer;
  28.   PMergeArray = ^TMergeArray;
  29.   TMergeArray = array[0..0] of Pointer;
  30.  
  31. { TSub3Array defines the boundaries of a SubArray and determines if
  32.   the SubArray is full or not.
  33.   The MergeSort Algorithm is easier readable with this class.}
  34.   TSub3Array = class(TObject)
  35.   private
  36.     FMax: LongInt;
  37.   protected
  38.   public
  39.     FLeft: LongInt;  { - Initialized to 0. }
  40.     FRight: LongInt;  { - Initialized to 0. }
  41.     Full: Boolean;
  42.     constructor Create(MaxValue: LongInt);
  43.     destructor Destroy; override;
  44.     procedure Init(LeftEnd, RightEnd: LongInt);
  45.     procedure Next;
  46.   end;  { TSub3Array }
  47.  
  48. { TM3Array class }
  49.   TM3Array = class(TObject)
  50.   private
  51.     FLeftArray, FMidArray, FRightArray: TSub3Array;
  52.     FM3Array, TempArray, SwapArray: PMergeArray;
  53.     FCount: Integer;
  54.     fCapacity:Integer;
  55.     procedure SetCapacity(NewCapacity:Integer);
  56.     procedure Expand;
  57.   protected
  58.     function Get(Index: Integer): Pointer;
  59.     procedure Put(Index: Integer; Item: Pointer);
  60.     procedure Merge(SorCompare: TMergeCompare);
  61.   public
  62.     destructor Destroy; override;
  63.     function Add(Item: Pointer): Integer;
  64.     procedure Clear;
  65.     function Last: Pointer;
  66.     procedure MergeSort(SorCompare: TMergeCompare);
  67.     property Count: Integer read FCount write FCount;
  68.     property Items[Index: Integer]: Pointer read Get write Put; default;
  69.     property M3Array: PMergeArray read FM3Array;
  70.     property Capacity:Integer read fCapacity write SetCapacity;
  71.   published
  72.   end;   { TM3Array }
  73.  
  74.   TmIOBuffer = class(TObject)
  75.   private
  76.     fBuffFile: File;
  77.     fFileName: String;
  78.     fFilledSize:Longint;
  79.     fBufferSize: LongInt;
  80.     fBufferPos: LongInt;
  81.     fBuffer: Pointer;
  82.     fNeedFill: Boolean;
  83.     fEof:Boolean;
  84.     fFileEof: Boolean;
  85.     FRecCount: Cardinal;
  86.     fSize:Longint;
  87.     fDataLen:Longint;
  88.     procedure AllocBuffer(NewValue:Longint);
  89.   protected
  90.   public
  91.     constructor create(FileName: string; DataLen, BuffSize: Integer);
  92.     destructor destroy;override;
  93.     procedure FillBuffer;
  94.     function ReadData:Pointer;
  95.     procedure WriteData(Var NewData);
  96.     procedure FlushBuffer;
  97.     procedure CloseBuffFile;
  98.     procedure DeleteBuffFile;
  99.     property Eof:Boolean read fEof;
  100.     property RecCount: Cardinal read FRecCount;
  101.     property Size:Longint read fSize;
  102.     property DataLen:Longint read fDataLen;
  103.   published
  104.   end;  { TmIOBuffer }
  105.  
  106.   TTempFile = class(TObject)
  107.   private
  108.     fFileName: String;
  109.     Reader: TmIOBuffer;
  110.     fFull:Boolean;
  111.   protected
  112.   public
  113.     FLeft: Pointer;
  114.     constructor Create;
  115.     destructor Destroy; override;
  116.     procedure Next;
  117.     procedure Init(FileName: String);
  118.     property Full:Boolean read fFull;
  119.   published
  120.   end;  { TTempFile }
  121.  
  122.   TMergeFile = class(TObject)
  123.   private
  124.     FFileOne, FFileTwo, FFileThree: TTempFile;
  125.     Writer: TmIOBuffer;
  126.     fInList, fOutList, TempList: TStringList;
  127.     fFileName:String;
  128.   protected
  129.   public
  130.     constructor Create(InList: TStringList);
  131.     destructor Destroy; override;
  132.     procedure FileMerge(MergeCompare: TMergeCompare);
  133.     procedure MergeSort(MergeCompare: TMergeCompare);
  134.     property FileName:String read fFileName;
  135.   published
  136.   end;  { TMergeFile }
  137.  
  138.   TFixRecSort = class(TObject)
  139.   private
  140.     Reader, Writer: TmIOBuffer;
  141.     FMaxLines: LongInt;
  142.     fMerArray: TM3Array;
  143.     MergeFile: TMergeFile;
  144.     fFileName: String;
  145.     fTempFileList: TStringList;
  146.     fCompare: TMergeCompare;
  147.     fMaxMem:LongInt;
  148.     function GetMaxMem:LongInt;
  149.     procedure SetMaxMem(value:LongInt);
  150.   protected
  151.   public
  152.     constructor Create(RecLen: LongInt);
  153.     destructor Destroy; override;
  154.     procedure Start(Compare: TMergeCompare);
  155.     procedure Init(FileName: String);
  156.     property MaxLines: LongInt read FMaxLines write FMaxLines default 60000;
  157.     property MaxMem:LongInt read GetMaxMem write SetMaxMem;
  158.   published
  159.   end;   { TFixRecSort }
  160.  
  161. Var FRecLen, fBuffersSize: Integer;
  162.  
  163. implementation
  164.  
  165. constructor TSub3Array.Create(MaxValue: LongInt);
  166.   begin
  167.     FLeft := 0;
  168.     FRight := 0;
  169.     Full := False;
  170.     FMax := MaxValue;
  171.   end;  { Create }
  172.  
  173. procedure TSub3Array.Init(LeftEnd, RightEnd: LongInt);  { public }
  174.   begin
  175.     FLeft:= LeftEnd;
  176.     FRight:= RightEnd;
  177.     if FLeft > FMax then Full:= False else Full:= True;
  178.   end;  { Init }
  179.  
  180. procedure TSub3Array.Next;
  181.   begin
  182.     inc(FLeft);
  183.     if (FLeft > FRight) or (FLeft > FMax) then Full:= False;
  184.   end;  { Next }
  185.  
  186. destructor TSub3Array.Destroy;
  187.   begin
  188.     inherited Destroy;
  189.   end;  { Destroy }
  190.  
  191. { TM3Array }
  192. destructor TM3Array.Destroy;
  193. begin
  194.   Clear;
  195.   inherited Destroy;
  196. end;
  197.  
  198. function TM3Array.Add(Item: Pointer): Integer;
  199. begin
  200.   Result := FCount;
  201.   if Result = FCapacity then Expand;
  202.   FM3Array[Result] := Item;
  203.   Inc(FCount);
  204. end;
  205.  
  206. procedure TM3Array.Expand;
  207. begin
  208.   SetCapacity(FCapacity + 8192);
  209. end;
  210.  
  211. procedure TM3Array.SetCapacity(NewCapacity:Integer);
  212. begin
  213.   FCapacity:= NewCapacity;
  214.   ReallocMem(FM3Array, FCapacity * SizeOf(Pointer));
  215.   ReallocMem(TempArray, FCapacity * SizeOf(Pointer));
  216. end;
  217.  
  218. procedure TM3Array.Clear;
  219. begin
  220.   FCount:= 0;
  221.   ReallocMem(TempArray, 0);
  222.   ReallocMem(FM3Array, 0);
  223.   FCapacity:= 0;
  224. end;
  225.  
  226. function TM3Array.Get(Index: Integer): Pointer;
  227. begin
  228.   Result := FM3Array[Index];
  229. end;
  230.  
  231. function TM3Array.Last: Pointer;
  232. begin
  233.   Result := Get(FCount - 1);
  234. end;
  235.  
  236. procedure TM3Array.Put(Index: Integer; Item: Pointer);
  237. begin
  238.   FM3Array[Index] := Item;
  239. end;
  240.  
  241. {This is a three way merge routine.
  242.  Unfortunately the " Merge " routine needs additional memory
  243.  An Algorithm to perform merging in linear time without extra space
  244.  is described in:
  245.  B. Huang and M. Langston, " Practical In-place Merging ",
  246.  Communications of the ACM 31(1988), 348-352. }
  247. procedure TM3Array.Merge(SorCompare: TMergeCompare);
  248. var
  249.   TempPos : integer;
  250. begin
  251.   TempPos := FLeftArray.FLeft;
  252.    while ( FLeftArray.Full ) and ( FMidArray.Full ) and ( FRightArray.Full ) do  {Main Loop}
  253.     begin
  254.       if SorCompare(FM3Array[FLeftArray.FLeft], FM3Array[FMidArray.FLeft]) <= 0 then
  255.         begin
  256.           if SorCompare(FM3Array[FLeftArray.FLeft], FM3Array[FRightArray.FLeft]) <= 0 then
  257.             begin
  258.               TempArray[ TempPos ] := FM3Array[ FLeftArray.FLeft ];
  259.               FLeftArray.Next;
  260.             end
  261.           else
  262.             begin
  263.               TempArray[ TempPos ] := FM3Array[ FRightArray.FLeft ];
  264.               FRightArray.Next;
  265.             end;
  266.         end
  267.       else
  268.         begin
  269.           if SorCompare(FM3Array[FMidArray.FLeft], FM3Array[FRightArray.FLeft]) <= 0 then
  270.             begin
  271.               TempArray[ TempPos ] := FM3Array[ FMidArray.FLeft ];
  272.               FMidArray.Next;
  273.             end
  274.           else
  275.             begin
  276.               TempArray[ TempPos ] := FM3Array[ FRightArray.FLeft ];
  277.               FRightArray.Next;
  278.             end;
  279.         end;
  280.           inc(TempPos);
  281.     end;
  282.  
  283.    while ( FLeftArray.Full ) and ( FMidArray.Full ) do
  284.     begin
  285.       if SorCompare(FM3Array[FLeftArray.FLeft], FM3Array[FMidArray.FLeft]) <= 0 then
  286.         begin
  287.           TempArray[ TempPos ] := FM3Array[ FLeftArray.FLeft ];
  288.           FLeftArray.Next;
  289.         end
  290.       else
  291.         begin
  292.           TempArray[ TempPos ] := FM3Array[ FMidArray.FLeft ];
  293.           FMidArray.Next;
  294.         end;
  295.           inc(TempPos);
  296.     end;
  297.  
  298.   while ( FMidArray.Full ) and ( FRightArray.Full ) do
  299.     begin
  300.       if SorCompare(FM3Array[FMidArray.FLeft], FM3Array[FRightArray.FLeft]) <= 0 then
  301.         begin
  302.           TempArray[ TempPos ] := FM3Array[ FMidArray.FLeft ];
  303.           FMidArray.Next;
  304.         end
  305.       else
  306.         begin
  307.           TempArray[ TempPos ] := FM3Array[ FRightArray.FLeft ];
  308.           FRightArray.Next;
  309.         end;
  310.           inc(TempPos);
  311.     end;
  312.  
  313.   while ( FLeftArray.Full ) and ( FRightArray.Full ) do
  314.     begin
  315.       if SorCompare(FM3Array[FLeftArray.FLeft], FM3Array[FRightArray.FLeft]) <= 0 then
  316.         begin
  317.           TempArray[ TempPos ] := FM3Array[ FLeftArray.FLeft ];
  318.           FLeftArray.Next;
  319.         end
  320.       else
  321.         begin
  322.           TempArray[ TempPos ] := FM3Array[ FRightArray.FLeft ];
  323.           FRightArray.Next;
  324.         end;
  325.           inc(TempPos);
  326.     end;
  327.  
  328.  while FLeftArray.Full do    { Copy Rest of First Sub3Array }
  329.     begin
  330.       TempArray[ TempPos ] := FM3Array[ FLeftArray.FLeft ];
  331.       inc(TempPos); FLeftArray.Next;
  332.     end;
  333.  
  334.   while FMidArray.Full do    { Copy Rest of Second Sub3Array }
  335.     begin
  336.       TempArray[ TempPos ] := FM3Array[ FMidArray.FLeft ];
  337.       inc(TempPos); FMidArray.Next;
  338.     end;
  339.  
  340.  while FRightArray.Full do   { Copy Rest of Third Sub3Array }
  341.     begin
  342.       TempArray[ TempPos ] := FM3Array[ FRightArray.FLeft ];
  343.       inc(TempPos); FRightArray.Next;
  344.     end;
  345.  
  346. end;  { Merge }
  347.  
  348. {Non-recursive Mergesort.
  349.  Very fast, if enough memory available.
  350.  The number of comparisions used is nearly optimal, about 3/4 of QuickSort.
  351.  If comparision plays a very more important role than exchangement,
  352.  it outperforms QuickSort in any case.
  353.  ( Large keys in pointer arrays, for example text with few short lines. )
  354.  From all Algoritms with O(N lg N) it's the only stable, meaning it lefts
  355.  equal keys in the order of input. This may be important in some cases. }
  356. procedure TM3Array.MergeSort(SorCompare: TMergeCompare);
  357. var
  358.   a, b, c, N, todo: LongInt;
  359. begin
  360.   FLeftArray:= TSub3Array.Create(FCount -1);
  361.   FMidArray:= TSub3Array.Create(FCount -1);
  362.   FRightArray:= TSub3Array.Create(FCount -1);
  363.   N:= 1;
  364.   repeat
  365.       todo:= 0;
  366.       repeat
  367.         a:= todo;
  368.         b:= a +N;
  369.         c:= b +N;
  370.         todo:= C +N;
  371.         FLeftArray.Init(a, b -1);
  372.         FMidArray.Init(b, c -1);
  373.         FRightArray.Init(c, todo -1);
  374.         Merge(SorCompare);
  375.       until todo >= Fcount;
  376.       SwapArray:= FM3Array; {Alternating use of the arrays.}
  377.       FM3Array:= TempArray;
  378.       TempArray:= SwapArray;
  379.       N:= N+ N +N;
  380.     until N >= Fcount;
  381.     FLeftArray.Free;
  382.     FMidArray.Free;
  383.     FRightArray.Free;
  384. end;  { MergeSort }
  385.  
  386. constructor TmIOBuffer.create(FileName: string; DataLen, BuffSize: Integer);
  387. var
  388.   fHandle: Integer;
  389. begin
  390.   inherited create;
  391.   FDataLen:= DataLen;
  392.   fFileName:= FileName;
  393.   if not FileExists(FileName) then
  394.   begin
  395.     fHandle:= FileCreate(FileName);
  396.     FileClose(fHandle);
  397.   end;
  398.   fBufferSize:= BuffSize;
  399.   FRecCount:= BuffSize Div DataLen;
  400.   fBufferSize:= DataLen *FRecCount;
  401.   AssignFile(fBuffFile, FileName);
  402.   Reset(fBuffFile, 1);
  403.   fSize:= FileSize(fBuffFile);
  404.   fNeedFill:= True;
  405.   fEof:= False;
  406.   fFileEof:= False;
  407.   AllocBuffer(fBufferSize);
  408.   fBufferPos:= 0;
  409. end;  { create }
  410.  
  411. destructor TmIOBuffer.destroy;
  412. begin
  413.   ReallocMem(fBuffer, 0);
  414.   CloseBuffFile;
  415.   inherited destroy;
  416. end;  { destroy }
  417.  
  418. procedure TmIOBuffer.AllocBuffer(NewValue:Longint);
  419. begin
  420.   fFilledSize:= fBufferSize;
  421.   ReallocMem(fBuffer, fBufferSize);
  422. end; { SetBufferSize }
  423.  
  424. procedure TmIOBuffer.FillBuffer;
  425. var
  426.   Readed: LongInt;
  427. begin
  428.   BlockRead(fBuffFile, fBuffer^, fBufferSize, Readed);
  429.   if FilePos(FBuffFile) = FSize then fFileEof:= True;
  430.   fBufferPos:= 0;
  431.   fFilledSize:= Readed;
  432.   fNeedFill:= False;
  433. end;   { FillBuffer }
  434.  
  435. function TmIOBuffer.ReadData:Pointer;
  436. begin
  437.   fEof:= False;
  438.   if fNeedFill then FillBuffer;
  439.   Result:= Pointer(Integer(fBuffer) + fBufferPos);
  440.   inc(fBufferPos, fDataLen);
  441.   if fBufferPos >= fFilledSize then
  442.   begin
  443.     fNeedFill:= True;
  444.     if FFileEof then FEof:= True;
  445.   end;
  446. end;   { ReadData }
  447.  
  448. procedure TmIOBuffer.WriteData(Var NewData);
  449. var
  450.   Pos: LongInt;
  451. begin
  452.   if (fBufferPos >= 0) and (Pointer(NewData) <> nil) then
  453.   begin
  454.     Pos := fBufferPos + fDataLen;
  455.     if Pos > 0 then
  456.     begin
  457.       if Pos >= FBufferSize then
  458.         begin
  459.            FlushBuffer;
  460.         end;
  461.       Move(NewData, Pointer(LongInt(fBuffer) + fBufferPos)^, fDataLen);
  462.       inc(fBufferPos, fDataLen);
  463.     end;
  464.   end;
  465. end;  { WriteData }
  466.  
  467. procedure TmIOBuffer.FlushBuffer;
  468. var
  469.   Written: LongInt;
  470. begin
  471.   BlockWrite(fBuffFile, fBuffer^, fBufferPos, Written);
  472.   fBufferPos:= 0;
  473. end;  { FlushBuffer }
  474.  
  475. procedure TmIOBuffer.CloseBuffFile;
  476. begin
  477.   CloseFile(fBuffFile);
  478. end;  { CloseBuffFile }
  479.  
  480. procedure TmIOBuffer.DeleteBuffFile;
  481. begin
  482.   SysUtils.DeleteFile(fFileName);
  483. end;  { DeleteBuffFile }
  484.  
  485. constructor TTempFile.Create;
  486. begin
  487.   inherited Create;
  488.    fFull:= False;
  489. end;  { Create }
  490.  
  491. procedure TTempFile.Init(FileName: String);
  492. begin
  493.   fFull:= False;
  494.   fFileName:= FileName;
  495.   if fFileName <> '' then
  496.     begin
  497.       Reader:= TmIOBuffer.create(fFileName, FRecLen, fBuffersSize);
  498.       if not Reader.Eof then
  499.         begin
  500.           fLeft:= Reader.ReadData;
  501.           fFull:= True;
  502.         end
  503.       else
  504.         begin
  505.           Reader.Free;
  506.           SysUtils.DeleteFile(fFileName);
  507.           fFileName:= '';
  508.         end;
  509.     end;
  510. end; { Init }
  511.  
  512. procedure TTempFile.Next;
  513. begin
  514.   if not Reader.Eof then
  515.     begin
  516.       fLeft:= Reader.ReadData;
  517.       fFull:= True;
  518.     end
  519.   else
  520.     begin
  521.       fFull:= False;
  522.       if fFileName <> '' then
  523.       begin
  524.         Reader.Free;
  525.         SysUtils.DeleteFile(fFileName);
  526.         fFileName:= '';
  527.       end;
  528.     end
  529. end;  { Next }
  530.  
  531. destructor TTempFile.Destroy;
  532. begin
  533.   if fFileName <> '' then
  534.   begin
  535.     Reader.Free;
  536.     SysUtils.DeleteFile(fFileName);
  537.   end;
  538.   inherited Destroy;
  539. end;  { Destroy }
  540.  
  541.  
  542. constructor TMergeFile.Create(InList: TStringList);
  543. begin
  544.   inherited Create;
  545.   fInList:= InList;
  546. end;  { Create }
  547.  
  548. destructor TMergeFile.Destroy;
  549. begin
  550.   inherited Destroy;
  551. end;  { Destroy }
  552.  
  553. procedure TMergeFile.FileMerge(MergeCompare: TMergeCompare);
  554. begin
  555.  
  556.   while ( FFileOne.Full ) and ( FFileTwo.Full ) and ( FFileThree.Full ) do
  557.     begin
  558.       if MergeCompare(FFileOne.FLeft, FFileTwo.FLeft) <= 0 then
  559.         begin
  560.           if MergeCompare(FFileOne.FLeft, FFileThree.FLeft) <= 0 then
  561.             begin
  562.               Writer.WriteData(FFileOne.fLeft^);
  563.               FFileOne.Next;
  564.             end
  565.           else
  566.             begin
  567.               Writer.WriteData(FFileThree.fLeft^);
  568.               FFileThree.Next;
  569.             end;
  570.         end
  571.       else
  572.         begin
  573.           if MergeCompare(FFileTwo.FLeft, FFileThree.FLeft) <= 0 then
  574.             begin
  575.               Writer.WriteData(FFileTwo.fLeft^);
  576.               FFileTwo.Next;
  577.             end
  578.           else
  579.             begin
  580.               Writer.WriteData(FFileThree.fLeft^);
  581.               FFileThree.Next;
  582.             end;
  583.         end;
  584.     end;
  585.  
  586.   while ( FFileOne.Full ) and ( FFileTwo.Full ) do
  587.     begin
  588.       if MergeCompare(FFileOne.FLeft, FFileTwo.FLeft) <= 0 then
  589.         begin
  590.           Writer.WriteData(FFileOne.fLeft^);
  591.           FFileOne.Next;
  592.         end
  593.       else
  594.         begin
  595.           Writer.WriteData(FFileTwo.fLeft^);
  596.           FFileTwo.Next;
  597.         end;
  598.     end;
  599.  
  600.   while ( FFileOne.Full ) and ( FFileThree.Full ) do
  601.     begin
  602.       if MergeCompare(FFileOne.FLeft, FFileThree.FLeft) <= 0 then
  603.         begin
  604.           Writer.WriteData(FFileOne.fLeft^);
  605.           FFileOne.Next;
  606.         end
  607.       else
  608.         begin
  609.           Writer.WriteData(FFileThree.fLeft^);
  610.           FFileThree.Next;
  611.         end;
  612.     end;
  613.  
  614.   while ( FFileTwo.Full ) and ( FFileThree.Full ) do
  615.     begin
  616.       if MergeCompare(FFileTwo.FLeft, FFileThree.FLeft) <= 0 then
  617.         begin
  618.           Writer.WriteData(FFileTwo.fLeft^);
  619.           FFileTwo.Next;
  620.         end
  621.       else
  622.         begin
  623.           Writer.WriteData(FFileThree.fLeft^);
  624.           FFileThree.Next;
  625.         end;
  626.     end;
  627.  
  628.   while FFileOne.Full do    { Write Rest of First SubFile }
  629.     begin
  630.       Writer.WriteData(FFileOne.fLeft^);
  631.       FFileOne.Next;
  632.     end;
  633.  
  634.   while FFileTwo.Full do    { Write Rest of Second SubFile }
  635.     begin
  636.       Writer.WriteData(FFileTwo.fLeft^);
  637.       FFileTwo.Next;
  638.     end;
  639.  
  640.   while FFileThree.Full do   { Write Rest of Third SubFile }
  641.     begin
  642.       Writer.WriteData(FFileThree.fLeft^);
  643.       FFileThree.Next;
  644.     end;
  645.  
  646. end; { FileMerge }
  647.  
  648. procedure TMergeFile.MergeSort(MergeCompare: TMergeCompare);
  649. var
  650.   a, b, c: String;
  651.   N, todo: LongInt;
  652. begin
  653.   fOutList:= TStringList.Create;
  654.   fOutList.Clear;
  655.   todo:= 0;
  656.   N:= fInList.Count;
  657.   fFileOne:= TTempFile.Create;
  658.   fFileTwo:= TTempFile.Create;
  659.   fFileThree:= TTempFile.Create;
  660.   while fInList.Count > 1 do
  661.   begin
  662.     while todo < fInList.Count do
  663.     begin
  664.       fFileName:= 'Temp' + IntToStr(N);
  665.       inc(N);
  666.       Writer:= TmIOBuffer.create(fFileName, fRecLen, fBuffersSize*3);
  667.       fOutList.Add(fFileName);
  668.       a:= fInList.Strings[todo]; inc(todo);
  669.       if todo < fInList.Count then begin b:= fInList.Strings[todo]; inc(todo) end else b:= '';
  670.       if todo < fInList.Count then begin c:= fInList.Strings[todo]; inc(todo) end else c:= '';
  671.       FFileOne.Init(a);
  672.       FFileTwo.Init(b);
  673.       FFileThree.Init(c);
  674.       FileMerge(MergeCompare);
  675.       Writer.FlushBuffer;
  676.       Writer.Free;
  677.       if todo = fInList.Count -1 then
  678.         begin
  679.           fOutList.Add(fInList.Strings[todo]);
  680.           inc(todo);
  681.         end;
  682.     end;
  683.       todo:= 0;
  684.       TempList:= fInList;
  685.       fInList:= fOutList;
  686.       fOutList:= TempList;
  687.       fOutList.Clear;
  688.   end;
  689.     fFileOne.Free;
  690.     fFileTwo.Free;
  691.     fFileThree.Free;
  692.     fOutList.Free
  693. end;  { MergeSort }
  694.  
  695. constructor TFixRecSort.Create(RecLen: LongInt);
  696. begin
  697.   inherited Create;
  698.   FRecLen:= RecLen;
  699.   fFileName:= '';
  700.   FMaxLines := 60000;
  701. end;  { Create }
  702.  
  703. procedure TFixRecSort.Init(FileName: String);
  704. begin
  705.   fFileName:= FileName;
  706.   fTempFileList:= TStringList.Create;
  707. end;
  708.  
  709. function TFixRecSort.GetMaxMem:LongInt;
  710. begin
  711.   Result:= fMaxMem;
  712. end;   { GetMaxMem }
  713.  
  714. procedure TFixRecSort.SetMaxMem(value:LongInt);
  715. var
  716.   RecLenPlus, CountRec: Integer;
  717. begin
  718.   if Value < 100000 then Value:= 100000;
  719.   if Value > 10000000 then Value:= 10000000;
  720.   fBuffersSize:= value div 6;
  721.   RecLenPlus:= FRecLen +8;
  722.   CountRec:= fBuffersSize div RecLenPlus;
  723.   fBuffersSize:= CountRec *FRecLen;
  724.   fMaxMem:= Value;
  725. end;  { SetMaxMem }
  726.  
  727. procedure TFixRecSort.Start(Compare: TMergeCompare);
  728. var
  729.   TempFileName, BackFileName, InFileName: String;
  730.   I, K: Integer;
  731.   SorData: Pointer;
  732. begin
  733.   FCompare:= Compare;
  734.   I:= 0;
  735.   InFileName:= fFileName;
  736.   BackFileName:= ChangeFileExt(fFileName, '.bak');
  737.   if FileExists(BackFileName) then DeleteFile(PChar(BackFileName));
  738.   Reader:= TmIOBuffer.create(FFileName, fRecLen, fBuffersSize *5);
  739.   while not Reader.Eof do
  740.   begin
  741.     fMerArray:= TM3Array.Create;
  742.     TempFileName:= 'Temp' + IntToStr(I);
  743.     fTempFileList.Add(TempFileName);
  744.     Writer:= TmIOBuffer.create(TempFileName, fRecLen, fBuffersSize);
  745.     inc(I);
  746.     while (fMerArray.Count < fMaxLines) and (fMerArray.Count <= Reader.RecCount) and (not Reader.Eof) do
  747.     begin
  748.       SorData:= Reader.ReadData;
  749.       fMerArray.Add(SorData);
  750.     end;        { while }
  751.     fMerArray.MergeSort(fCompare);
  752.     for K := 0 to  fMerArray.Count -1 do       { Iterate }
  753.     begin
  754.       SorData:= fMerArray[K];
  755.       Writer.WriteData(SorData^);
  756.     end;        { for }
  757.     Writer.FlushBuffer;
  758.     Writer.Free;
  759.     fMerArray.Free;
  760.   end;        { while }
  761.   Reader.Free;
  762.   if fTempFileList.Count > 1 then
  763.   begin
  764.     MergeFile:= TMergeFile.Create(fTempFileList);
  765.     MergeFile.MergeSort(fCompare);
  766.     RenameFile(InFileName, BackFileName);
  767.     RenameFile(MergeFile.FileName, FFileName);
  768.     MergeFile.Free;
  769.   end else
  770.   begin
  771.     RenameFile(InFileName, BackFileName);
  772.     RenameFile(TempFileName, FFileName);
  773.   end;
  774. end;  { Start }
  775.  
  776. destructor TFixRecSort.Destroy;
  777. begin
  778.   inherited Destroy;
  779. end;  { Destroy }
  780.  
  781. end.
  782. {--------------------------------------------------------------------}
  783. { Martin Waldenburg
  784.   Landaeckerstrasse 27
  785.   71642 Ludwigsburg
  786.   Germany
  787.   Share your Code}
  788. {--------------------------------------------------------------------}
  789.